home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / graphics / 3dvect37.zip / PMODE.DOC < prev    next >
Text File  |  1994-06-22  |  31KB  |  647 lines

  1.  
  2.   Greetings... This is the documentation for PMODE v2.4 assembly protected
  3. mode header by Tran (a.k.a. Thomas Pytel). It is intended for assembly
  4. programmers with a good deal of knowlege of the 386. In this doc is explained
  5. the workings and usage of PMODE.ASM.
  6.  
  7. ------------------------------------------------------------------------------
  8. Contents:
  9. ---------
  10.  
  11.   0 - Overview
  12.       0.0 - What it does
  13.       0.1 - Your code
  14.   1 - Memory, segments, and selectors
  15.       1.0 - Memory structure
  16.       1.1 - Usage and DOS
  17.       1.2 - Selectors
  18.   2 - The stack and calling across modes
  19.       2.0 - The stack
  20.       2.1 - Calling real mode
  21.       2.2 - Calling protected mode
  22.   3 - IRQs and exceptions
  23.       3.0 - IRQs
  24.       3.1 - DPMI and the stack
  25.       3.2 - Chaining to real mode
  26.       3.3 - The IF flag
  27.       3.4 - Exceptions
  28.   4 - Functions and data
  29.       4.0 - Variables
  30.       4.1 - Memory functions
  31.       4.2 - IRQ functions
  32.       4.3 - Selector functions
  33.       4.4 - Other functions
  34.   5 - Notes
  35.       5.0 - DMA problems
  36.       5.1 - Misc notes
  37.       5.2 - Final word
  38.  
  39. ------------------------------------------------------------------------------
  40. 0 - Overview:
  41. -------------
  42.  
  43.   PMODE.ASM is a small piece of assembly code which is intended to allow for
  44. easy 32bit flat protected mode coding in assembly. I wrote it for myself, and
  45. it was designed for exactly what I need. But since it is so useful, and there
  46. are not too many other alternatives for protected mode ASM coding, I am
  47. putting it out for public distribution. The current version of PMODE has
  48. been evolving for a while. There has been plenty of time to refine and debug
  49. it. It is at this point, from my own and friends experiences, totally stable
  50. and bug-free. I do not make this statement lightly. But I do not guarantee it
  51. either.
  52.  
  53.   The biggest difference between this and the last released version of PMODE
  54. is the removal of INTs 34h and 35h. But dont worry, they are not necessary.
  55. Actually, the code for those INT handlers is still there, but no longer
  56. functioning. There were some minor problems under certain weird conditions.
  57. I did not find myself using them anyway. As it is now, PMODE does its job
  58. perfectly. If you have been looking for something like this, feel free to use
  59. it. Or examine the source code if you just want to learn (though the code is
  60. umm ... well ... a bit messy). All I ask if you use this code is credits.
  61.  
  62. 0.0 - What it does:
  63. -------------------
  64.  
  65.   PMODE provides a flat 32bit protected mode environment for assembly code to
  66. run in. No matter what kind of 386 protection control is already in place. It
  67. will run under VCPI, DPMI, or in raw mode with no 386 control system in place.
  68. This includes all the popular memory managers, Windows the virus, OS/2, etc...
  69. PMODE will take care of detecting a 386+ processor, making sure there is
  70. enough memory and allocating it. It will handle all the minor details of 386
  71. protected mode. Send IRQs that occur in protected mode to their real mode
  72. handlers, or allow you to intercept them. And, ofcourse, allow your protected
  73. mode code to call real mode interrupts and routines. PMODE will also take care
  74. of allocating and maintaining the stack across mode calls.
  75.  
  76.   When a PMODE program starts up, PMODE will do all of its necessary starup
  77. tasks. Then, if no error was detected (not enough mem, no 386+, etc...), it
  78. will jump to a label in your code called _main. Your program takes over from
  79. there with all interrupts disabled since real mode. You must do a STI to
  80. enable them. Dont forget this like I have so many times. When your program is
  81. done and wants to exit to DOS, simply jump to a label called _exit, defined
  82. in PMODE. You can pass back an error code to DOS. There is a variable called
  83. _exitcode which contains the byte to pass back to DOS (AL in INT 21h AH=4c).
  84.  
  85. 0.1 - Your code:
  86. ----------------
  87.  
  88.   All your 32bit code goes into one large CODE32 segment. It runs in 32bit
  89. protected mode from start to finish. All your code and data reside in this
  90. one large segment. Though you can read or write stuff below the beginning of
  91. CODE32. Within your code you will hardly ever have to worry about segment
  92. overrides or stuff like that. Its just pretty much straight flat assembly with
  93. full 32bit linear addresses for all your code and data. You can do most of the
  94. stuff you do in real mode. I would not suggest trying to go TSR or running
  95. external programs from your PMODE code though. It is doable, and will probably
  96. work, but PMODE was not designed for that. You would have to free up low
  97. memory yourself, and you cant free up high memory. There may be other minor
  98. problems uncompensated for. PMODE is meant for standalone ASM programs like
  99. games or demos, and does very well for that.
  100.  
  101. ------------------------------------------------------------------------------
  102. 1 - Memory, segments, and selectors:
  103. ------------------------------------
  104.  
  105.   In protected mode, your program has access to all free low and high memory
  106. that could be allocated. Low memory is all memory visible to DOS below 1M.
  107. High memory is all extended memory that could be allocated through VCPI, DPMI,
  108. XMS, or INT 15 AH=88h of raw mode. All this memory can be accessed directly
  109. realative to the beginning of the 32bit protected mode segment (CODE32). You
  110. can also access memory realative to the absolute beginning of memory. Three
  111. main selectors are set up by PMODE. One for the code segment starting at
  112. CODE32, its limit is set to 4G. One for a data segment alias for the code
  113. segment (same memory space), also at 4G. And one for a data segment beginning
  114. at the absolute beginning of memory. In fact, all selectors allocated by PMODE
  115. are set to a limit of 4G.
  116.  
  117. 1.0 - Memory structure:
  118. -----------------------
  119.  
  120.   The structure of memory when your code begins executing is as follows:
  121.  
  122. +-------------------------------------------------------------+
  123. | Normal crap (real mode int vector table, DOS, TSRs, etc...) |
  124. +-------------------------------------------------------------+
  125. | PSP                                                         |
  126. +-------------------------------------------------------------+
  127. | Beginning of CODE16 - PMODE 16bit code and data             |
  128. +-------------------------------------------------------------+
  129. | Beginning of CODE32 - PMODE 32bit code and data             |
  130. +-------------------------------------------------------------+
  131. | Your 32bit code and data                                    |
  132. +-------------------------------------------------------------+
  133. | The stack                                                   |
  134. +-------------------------------------------------------------+
  135. | PMODE data allocated at run-time (IDT, TSS, etc...)         |
  136. +-------------------------------------------------------------+
  137. | Free low memory (_lomembase to _lomemtop)                   |
  138. +-------------------------------------------------------------+
  139. | Video buffer, ROMS, also possibly hiram                     |
  140. +-------------------------------------------------------------+
  141. | Used extended memory (if any)                               |
  142. +-------------------------------------------------------------+
  143. | Free extended memory (if any, _himembase to _himemtop)      |
  144. +-------------------------------------------------------------+
  145.  
  146.   When your code begins execution at _main, you can be sure there is a minimum
  147. of low memory available. This number is specified at the top of PMODE.ASM as
  148. LOWMIN. There is also a minimum of high memory specified in PMODE.ASM as
  149. EXTMIN. The beginning and ending addresses of these memory spaces, realative
  150. to the beginning of CODE32, are defined in four variables made available to
  151. your code. _lowmembase is the linear address of the beginning of free low
  152. memory. _lowmemtop is the linear address of the top of low memory (last
  153. possible byte+1). _himembase is the beginning of extended memory, and
  154. _himemtop is the end of it. All of these vars can be modified by your program.
  155. They will also be modified by PMODE memory functions. See section 4 for a
  156. description of these functions. Basically all that they do is see if there is
  157. enough memory available for a block you request. If there is, they pass back
  158. a pointer to the base of free memory of the type you requested, then adjust
  159. that base by the amount you requested.
  160.  
  161.   The functions (just tiny stubs of code really) provided for memory are just
  162. straight linear functions. No management of blocks of memory is done. I
  163. personally dont like fragmentations of memory, and can work fine without the
  164. need for blocks. If you want, write yourself a little malloc library if that
  165. is what you need.
  166.  
  167. 1.1 - Usage and DOS:
  168. --------------------
  169.  
  170.   When you call real mode DOS interrupts, or any real mode procedure that
  171. expects a buffer, you will have to make sure that buffer is in low memory.
  172. Remember that real mode DOS and code can only see low memory. Your code and
  173. data and the stack always reside in low memory. If you want to pass something
  174. that is in high memory however, you will have to copy it to somewhere in low
  175. memory. Once in low memory, you will have to get the real mode segment:offset
  176. pair for your linear address. Figuring this out is very easy. All linear
  177. addresses in PMODE are realative to the beginning of the CODE32 segment. To
  178. convert to an absolute address, all you have to do is add the offset of the
  179. CODE32 segment from absolute 0. And just this value is available in a variable
  180. called _code32a. All this really is, is the real mode segment value of CODE32
  181. shifted left 4 bits. So for example, _lomembase+_code32a is the linear address
  182. of the beginning of free low memory from absolute 0. And if you dont know how
  183. to convert this type of address to a seg:off pair, you should probably not be
  184. reading this doc just yet.
  185.  
  186. 1.2 - Selectors:
  187. ----------------
  188.  
  189.   As you know (and if you dont, get some books and learn more about protected
  190. mode), in protected mode the segment registers dont work with segment
  191. addresses, but with selectors. Selectors are indexes into tables describing
  192. segments. Appropriately enough these tables are called descriptor tables. And
  193. you do not have to worry about them, PMODE takes care of all the crap
  194. associated with them.
  195.  
  196.   The three main selectors you need (the code, data, and zero selectors) are
  197. set up by PMODE. Their numerical values are stored in three variables made
  198. available to your program. _selcode, _seldata, and _selzero are these
  199. variables. When your program begins execution at _main, CS is obviously set
  200. to _selcode, DS, ES, FS, and SS to _seldata, and GS is set to _selzero. With
  201. the exception of FS and SS, this is the state PMODE expects the segment regs
  202. to be whenever you call one of its functions or interrupts.
  203.  
  204.   PMODE also allows you to allocate extra data selectors and to set their base
  205. addresses to anything you want. This could be useful for tight routines where
  206. you want to conserve register space and use 16bit register addressing. You
  207. can specify the maximum number of selectors you will need to have allocated
  208. at any one time at the top of PMODE.ASM in the SELECTORS equate.
  209.  
  210.   During the execution of your code, you can modify DS, ES, FS, and GS to
  211. whatever selector you wish. Just remember to set the appropriate values for
  212. DS, ES, and GS before calling and PMODE functions or interrupts. Throughout
  213. the execution of your program you can assume SS to be _seldata. Except in the
  214. special case of IRQ handlers, explained in section 3.
  215.  
  216. ------------------------------------------------------------------------------
  217. 2 - The stack and calling across modes:
  218. ---------------------------------------
  219.  
  220.   The stack and calling across modes are closely tied together. Multiple
  221. nested calls from protected to real mode and back are supported. DPMI also
  222. feels the need to complicate the situation a little in dealing with IRQs, but
  223. more on that later. You do not have to worry about the stack in calling across
  224. modes, PMODE will take care of it.
  225.  
  226. 2.0 - The stack:
  227. ----------------
  228.  
  229.   PMODE sets up and maintains the stack for your program. In fact, your code
  230. should not attempt to set up its own stack. Both because its not necessary,
  231. and because of some other stupid historical reasons that I have forgotten by
  232. now. There are four equates at the top of PMODE.ASM that determine the final
  233. size and allocation of the stack. STAKMAIN sets the size of your main program
  234. stack. The stack that will be used in your main stream of execution. STAKRMODE
  235. is the size of the stack that will be given to any real mode code that is
  236. called from protected mode. STAKPMODE is the size of the stack given to any
  237. protected mode routines called from real mode. MODENESTING is the maximum
  238. number of nested cross-mode calls supported. The final size of the master
  239. stack is determined from all of these variables, and it cannot exceed 64k.
  240.  
  241. 2.1 - Calling real mode:
  242. ------------------------
  243.  
  244.   From your protected mode code you can call real mode interrupts and routines
  245. using protected mode interrupts set up by PMODE for this purpose. You pass
  246. registers to the real mode interrupt or routine through the use of virtual
  247. registers, which are just memory images of the values to be set for those
  248. registers in real mode. There are virtual registers for EAX, EBX, ECX, EDX,
  249. ESI, EDI, EBP, DS, ES, FS, and GS. The virtual registers for AL, AH, and AX
  250. share the appropriate memory space within the virtual EAX reg. Notice that
  251. there are no SS, ESP, CS, and EIP registers. CS:EIP is taken from the real
  252. mode interrupt vektor table for interrupt calls, and passed in the real CX:DX
  253. registers for a procedure call. SS:ESP is set up by PMODE.
  254.  
  255.   An INT 32h instruction in protected mode calls a real mode procedure. The
  256. real CX:DX registers are the seg:off of the real mode procedure. The real mode
  257. procedure must return with a RETF. The interrupt enable flag is preserved
  258. across the call to real mode, but not back. After the INT 32h the IF flag will
  259. be the same as before. The real carry, zero, aux, parity, sign, and overflow
  260. flags will be passed back from the real mode routine unchanged. The real CPU
  261. registers will be set to the values of the virtual registers for the real mode
  262. routine. The return values of the routine will be stored back into the virtual
  263. registers. The actual CPU registers will be unchanged in protected mode.
  264.  
  265.   An INT 33h in protected mode will call a real mode interrupt handler. AL is
  266. the interrupt number you want to call. The interrupt flag is disabled for the
  267. real mode interrupt handler just as it is in real mode. Other than this, INT
  268. 33h works just like INT 32h with respect to virtual registers and the real
  269. flags passed back from the handler.
  270.  
  271.   One minor thing I must point out. INT 32h and INT 33h do not preserve FS. It
  272. is returned as _seldata.
  273.  
  274. 2.2 - Calling protected mode:
  275. -----------------------------
  276.  
  277.   You can also call a protected mode routine from real mode. The virtual
  278. registers are used again to pass register values. With the exception of the
  279. segment registers. For the protected mode routine, CS will obviously be
  280. _selcode. DS, ES, FS, and SS will be _seldata. GS will be _selzero. Also, the
  281. direction flag will be cleared for the protected mode routine. The virtual
  282. DS, ES, FS, and GS registers are untouched by a call to a protected mode
  283. routine. The interrupt enable flag is preserved across the call, but not back,
  284. just like a protected mode call to INT 32h. The carry, zero, aux, parity,
  285. sign, and overflow flags are also passed back real mode from the protected
  286. mode routine. To call a protected mode routine from real mode, do an INT 32h
  287. in real mode. Thats right, another INT 32h. But its a different handler from
  288. the protected mode version of the int. The offset of the protected mode
  289. routine you want to call should be in EDX. And that routine must return with
  290. a regular RET.
  291.  
  292. ------------------------------------------------------------------------------
  293. 3 - IRQs and exceptions:
  294. ------------------------
  295.  
  296.   First thing, let me just say that many DPMI drivers are very buggy in the
  297. area of IRQs. They may not reflect them properly to real mode. Or they may
  298. screw up if you try to do a call to real mode from a protected mode IRQ
  299. handler. Keep this is mind if you are testing your code under a DPMI system.
  300.  
  301. 3.0 - IRQs:
  302. -----------
  303.  
  304.   By default, IRQs that occur in protected mode are sent on to their real mode
  305. handlers (this counts as a mode switch to the PMODE master stack). PMODE
  306. allows you to install your own protected mode IRQ handlers. There are two
  307. functions for getting and setting protected mode IRQ vectors in PMODE (see
  308. section 4). Once set with these functions, your protected mode IRQ handler
  309. will be active, but only in protected mode. If an IRQ you have hooked occurs
  310. while processing a call to real mode (INT 32h or 33h or an IRQ that is being
  311. processed by its real mode handler), it will go to the handler specified in
  312. the real mode interrupt vector table. PMODE provides another set of functions
  313. to create real mode callbacks to protected mode IRQ handlers, so that your
  314. handler will get control no matter where the IRQ occurred. These callbacks,
  315. however, modify the real mode interrupt vector table. Making chaining to the
  316. real mode handler not as easy as using INT 33h with the appropriate interrupt
  317. number.
  318.  
  319.   You should terminate any protected mode IRQs with an IRETD (notice the D).
  320. DPMI dox also say that this may not restore the interrupt enable flag, so
  321. you should do a STI just before. However, all DPMIs I have tested seem to
  322. restore the flag correctly without the STI.
  323.  
  324. 3.1 - DPMI, and the stack:
  325. --------------------------
  326.  
  327.   The one anomaly to PMODEs stack with IRQs is DPMI. It sees fit to switch
  328. onto its own stack whenever an IRQ goes off. And if you try to switch off that
  329. stack, you will be severely punished by DPMI. For this reason, calls to real
  330. mode (INT 32h, 33h) from IRQs under DPMI may or may not work depending on what
  331. DPMI youre running under and how buggy it is. I have had no problems with
  332. Windows DPMI driver in these situations, but you have been warned. Because
  333. DPMI switches onto its own stack, you can not assume anything about SS in IRQ
  334. handlers, and should definately not mess with it.
  335.  
  336. 3.2 - Chaining to real mode:
  337. ----------------------------
  338.  
  339.   If you dont set the real mode IRQ callback for a particular IRQ, chaining
  340. to that IRQs real mode handler is as easy as using INT 33h with the
  341. appropriate interrupt number. But you probably will set the callbacks. In
  342. which case, if you use INT 33h, it will just go to the protected mode IRQ
  343. handler. And if this INT 33h call was from the protected mode IRQ handler,
  344. well, lets just say infinite loop. If you have the callback set, and you wish
  345. to chain (why bother?), you must make the address of the real mode IRQ handler
  346. available to a real mode far routine that will call that handler as an
  347. interrupt routine. You should call this real mode routine with INT 32h from
  348. protected mode to do the IRQ chaining.
  349.  
  350. 3.3 - The IF flag:
  351. ------------------
  352.  
  353.   DPMI may need to virtualize the real system interrupt flag in protected
  354. mode. For this reason you may not assume anything about the IF flag and
  355. instructions which usually modify it. For example, PUSHF(D) may not store the
  356. actual IF flag on the stack, and POPF(D) may not change either the real IF
  357. flag or the virtual one. You can however be sure that CLI and STI will carry
  358. out their functions correctly. Also, PMODE will replicate DPMIs native
  359. interrupt flag functions if DPMI is not present. They are on INT 31h in
  360. protected mode and are as follows:
  361.  
  362.   AX=900h: Get state of IF then disable it. Returns AL set to the IF flag.
  363.   AX=901h: Get state of IF then enable it. Returns AL set to the IF flag.
  364.   AX=902h: Only returns AL set to the IF flag (0=disabled, 1=enabled).
  365.  
  366. 3.4 - Exceptions:
  367. -----------------
  368.  
  369.   Under DPMI, exceptions are handled by the DPMI driver, which will usually
  370. just terminate your program. Otherwise PMODE will automatically exit to DOS
  371. on any exception not overridden by the low 8 IRQs. Any exception that is, will
  372. erroneously be sent to that IRQ handler, be it a protected mode handler or
  373. a real mode handler. Hey, you should not be getting exceptions in the first
  374. place.
  375.  
  376. ------------------------------------------------------------------------------
  377. 4 - Functions and data:
  378. -----------------------
  379.  
  380.   PMODE makes some variables available to your program concerning the state of
  381. the system and memory. It also provides some functions for dealing with IRQs,
  382. memory, and selectors. These functions and vars are defined in PMODE.INC. Just
  383. include that somewhere in your code. Some of the functions are actually
  384. defined as dwords, not as near lables. This is because their address may be
  385. modified at startup to point to appropriate functions for the system type.
  386. Dont worry about this. Just call them as you would call normal functions. So
  387. here is a summary of all data and functions you can use. The functions
  388. definitions are pretty self-explanatory. Except maybe that CF=0 means carry
  389. flag clear, and CF=1 means a cheeseburger, hold the mayo.
  390.  
  391. 4.0 - Variables:
  392. ----------------
  393.  
  394. _selcode:word - The 32bit code selector.
  395.  
  396. _seldata:word - The 32bit data selector (alias for the code).
  397.  
  398. _selzero:word - The 32bit data selector starting at absolute 0.
  399.  
  400. _lomembase:dword - The linear address of the current base of low memory.
  401.  
  402. _lomemtop:dword - The linear address of the current top of low memory.
  403.  
  404. _himembase:dword - The linear address of the current base of high memory.
  405.  
  406. _himemtop:dword - The linear address of the current top of high memory.
  407.  
  408. _pspa:dword - The linear address of the PSP from absolute 0.
  409.  
  410. _code16a:dword - The linear address of the CODE16 segment from absolute 0.
  411.  
  412. _code32a:dword - The linear address of the CODE32 segment from absolute 0.
  413.  
  414. _sysbyte0:byte - The low 2 bits are the system type, 0=raw, 1=XMS, 2=VCPI,
  415.   3=DPMI. The high 6 bits are undefined.
  416.  
  417. _exitcode:byte - The exit code you want to pass to DOS, 0 by default.
  418.  
  419. Here are the virtual registers for cross-mode calls:
  420.  
  421.   v86r_eax:dword, v86r_ebx:dword, v86r_ecx:dword, v86r_edx:dword
  422.   v86r_esi:dword, v86r_edi:dword, v86r_ebp:dword
  423.   v86r_ah:byte, v86r_al:byte, v86r_bh:byte, v86r_bl:byte
  424.   v86r_ch:byte, v86r_cl:byte, v86r_dh:byte, v86r_dl:byte
  425.   v86r_ax:word, v86r_bx:word, v86r_cx:word, v86r_dx:word
  426.   v86r_si:word, v86r_di:word, v86r_bp:word
  427.   v86r_ds:word, v86r_es:word, v86r_fs:word, v86r_gs:word
  428.  
  429. 4.1 - Memory functions:
  430. -----------------------
  431.  
  432. _getlomem - Allocate some low mem
  433.   In:
  434.     EAX - size requested
  435.   Out:
  436.     CF=0 - memory allocated
  437.     CF=1 - not enough mem
  438.     EAX - linear pointer to mem or ?
  439.  
  440. _gethimem - Allocate some high mem
  441.   In:
  442.     EAX - size requested
  443.   Out:
  444.     CF=0 - memory allocated
  445.     CF=1 - not enough mem
  446.     EAX - linear pointer to mem or ?
  447.  
  448. _getmem - Allocate any mem, (first cheks low, then high)
  449.   In:
  450.     EAX - size requested
  451.   Out:
  452.     CF=0 - memory allocated
  453.     CF=1 - not enough mem
  454.     EAX - linear pointer to mem or ?
  455.  
  456. _lomemsize - Get amount of free low mem
  457.   Out:
  458.     EAX - number of bytes free
  459.  
  460. _himemsize - Get amount of free high mem
  461.   Out:
  462.     EAX - number of bytes free
  463.  
  464. 4.2 - IRQ functions:
  465. --------------------
  466.  
  467. _getirqvect - Get protected mode IRQ handler offset
  468.   In:
  469.     BL - IRQ num (0-0fh)
  470.   Out:
  471.     EDX - offset of IRQ handler
  472.  
  473. _setirqvect - Set protected mode IRQ handler offset
  474.   In:
  475.     BL - IRQ num (0-0fh)
  476.     EDX - offset of IRQ handler
  477.  
  478. _getirqmask - Get status of IRQ mask bit
  479.   In:
  480.     BL - IRQ num (0-15)
  481.   Out:
  482.     AL - status: 0=enabled, 1=disabled
  483.  
  484. _setirqmask - Set status of IRQ mask bit
  485.   In:
  486.     BL - IRQ num (0-15)
  487.     AL - status: 0=enabled, 1=disabled
  488.  
  489. _rmpmirqset - Set a real mode IRQ vect to redirect to pmode
  490.   In:
  491.     BL - IRQ number
  492.     EDX - offset of IRQ handler
  493.     EDI -> 21 byte buffer for code stub created
  494.   Out:
  495.     EAX - old seg:off of real mode IRQ handler
  496.  
  497. _rmpmirqfree - Reset a real more IRQ vect back to normal
  498.   In:
  499.     BL - IRQ number
  500.     EAX - seg:off of real mode IRQ handler
  501.  
  502. 4.3 - Selector functions:
  503. -------------------------
  504.  
  505. _getselector - Allocate a selector
  506.   Out:
  507.     CF=1 - selector not allocated
  508.     CF=0 - selector allocated
  509.     AX - 4G data selector or ?
  510.  
  511. _freeselector - Free an allocated selector
  512.   In:
  513.     AX - selector
  514.  
  515. _setselector - Set the base addx for a selector
  516.   In:
  517.     AX - selector
  518.     EDX - linear base addx for selector
  519.  
  520. 4.4 - Other functions:
  521. ----------------------
  522.  
  523. _exit - Exit to real mode
  524.  
  525. _ret - Absolutely nothing, just a RET instruction
  526.  
  527. ------------------------------------------------------------------------------
  528. 5 - Notes:
  529. ----------
  530.  
  531.   In this section is a whole bunch of info that didnt really fit into the
  532. other sections, or that I want to emphasize. If you run into a weird bug,
  533. check here to for some possibilities. It is easy to forget enable interrupts
  534. when your program gains control. Or to forget theres a limit to the stack
  535. since control of it is taken away from your program.
  536.  
  537. 5.0 - DMA Problems:
  538. -------------------
  539.  
  540.   As you know, the DMA controllers in the PC use all physical addresses.
  541. Nothing but the processor itself knows how linear memory is arranged in the
  542. physical memory banks. When paging is disabled, the relationship is very
  543. simple. The linear address is always the same as the physical address. But
  544. when you enable paging, that could get all screwed up. In raw mode and XMS,
  545. you dont have to worry about this since paging is disabled. But under VCPI
  546. and DPMI things are different. You can almost definately count on extended
  547. memory addresses not being consistent with their physical addresses. Low
  548. memory however, will usually map perfectly to its physical addresses. Unless
  549. the program is running in some sort of multitasking system. Then the chances
  550. are slim. The point is that you cant trust DMA much under VCPI and DPMI.
  551.  
  552.   Ive seen the specs for VDS, and its useless for the type of DMA I need to
  553. do. So there is no support for it in PMODE. If you feel like it, use it
  554. yourself if you detect it.
  555.  
  556. 5.1 - Misc notes:
  557. -----------------
  558.  
  559. ) No, you cant link PMODE with any high level languages.
  560.  
  561. ) When linking, PMODE must be the first object in the link list.
  562.  
  563. ) PMODE functions and INTs expect the direction flag to be clear.
  564.  
  565. ) In IRQ handlers, you should not assume anything about the stack.
  566.  
  567. ) Under VCPI, PMODE will allocate a maximum of 60M extended memory.
  568.  
  569. ) You do not have to free any selectors you allocate before exiting.
  570.  
  571. ) Remember to use 'IRETD' not 'IRET' at the end of protected mode IRQs.
  572.  
  573. ) Due to all of its 'evolving', PMODE.ASM is now very very very very messy.
  574.  
  575. ) I would REALLY suggest not ever switching your stack in protected mode
  576. yourself.
  577.  
  578. ) Remember that upon reaching '_main', interrupts are still disabled. Dont
  579. forget to do the STI.
  580.  
  581. ) You cant write to memory with a CS: override in protected mode, but you can
  582. read with a CS: override.
  583.  
  584. ) The functions _rmpmirqset and _rmpmirqfree have changed from the previous
  585. released version of PMODE.
  586.  
  587. ) This thing was coded under TASM 3.0. So if you have something different,
  588. dont blame me if it doesnt compile.
  589.  
  590. ) When doing multiple nested cross-mode calls, keep in mind that the same
  591. virtual regs are used to pass register values.
  592.  
  593. ) Division faults, single step interrupts, the NMI, INT3, INTO, and BOUND
  594. faults are sent to real mode handlers for the appropriate int number.
  595.  
  596. ) If you modify the base address of a selector you allocated, make sure to
  597. reload any segment registers containing that selector before using them.
  598.  
  599. ) I hope you realize that in PMODE IRQ handlers, you dont have the BIOS to
  600. redirect IRQ9 to IRQ2. So any device that uses IRQ2 will actually be using 9.
  601.  
  602. ) If youre getting problems that smell of stack trouble, try increasing the
  603. stack size vars at the top of PMODE.ASM and the maximum nesting level if youre
  604. doing many calls across modes.
  605.  
  606. ) Yeah, theres no debugger. Quit whining, dont you realize it runs under DPMI?
  607. So you can use any old DPMI debugger (though I have yet to find one that
  608. works, but I am sure you can).
  609.  
  610. ) Upon entry to a protected mode IRQ handler, remember that all segregs are
  611. in an unknown state, including DS. Dont forget the 'mov ds,cs:_seldata'. Also
  612. ofcourse preserve the previous value of all the regs.
  613.  
  614. ) Remember that the INT31 AX=9?? flag functions are only available in pmode.
  615. Go ahead, use the PUSHFs and POPFs in real mode to alter the IF flag... And
  616. any DPMI host that cant handle that properly deserves to crash.
  617.  
  618. ) There may be weird problems under some DPMIs. Many DPMI drivers out there
  619. are anywhere from a little to extremely buggy. If you suspect your DPMI
  620. driver, try running without it, or under a different DPMI driver.
  621.  
  622. ) If youre gonna add other segments, put them between CODE16 and CODE32 only
  623. if theyre small enough to still allow access to CODE32 data from CODE16.
  624. Otherwise put them between CODE32 and CODEEND. You can also just stick your
  625. 16bit code in the CODE16 segment.
  626.  
  627. ) Before exiting your program, you do not need to restore any protected mode
  628. IRQ vectors. If you modified the real mode vector table, you gotta restore
  629. those. And you do not have to restore the IRQ masks at 21h and A1h, PMODE
  630. stores them before jumping to _main, and restores them before exiting.
  631.  
  632. ) PMODE does not handle the VDISK low to high extended memory allocation
  633. scheme because it is just plain stupid (and does not seem to be used outside
  634. of XMS where its not a problem since the XMS driver is used to allocate mem).
  635. If you wanna take precautions for this type of allocation, make yourself a
  636. little macro to check for it and adjust _himembase accordingly.
  637.  
  638. 5.2 - Final word:
  639. -----------------
  640.  
  641.   Well thats that... If you have a problem with something in PMODE, code your
  642. own. The source for PMODE is included for instructional purposes mainly (if
  643. you can begin to understand it, Im not really sure I do anymore). Its overdue
  644. for a recoding, but that will have to wait till I feel like it. Hmm... but it
  645. works pretty well for me now. Oh well... L8r...
  646.  
  647.